{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python实现\n",
    "\n",
    "自定义了相关标题以识别"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "from typing import List\n",
    "\n",
    "class CompileItem:\n",
    "    def __init__(self, level, pattern_text):\n",
    "        self.level = level\n",
    "        self.pattern_text = pattern_text\n",
    "        self.pattern = re.compile(pattern_text)\n",
    "\n",
    "class TxtLevel:\n",
    "    def __init__(self, parent, weight, raw_level, standard_level, is_valid):\n",
    "        self.parent = parent\n",
    "        self.weight = weight\n",
    "        self.raw_level = raw_level\n",
    "        self.standard_level = standard_level\n",
    "        self.is_valid = is_valid\n",
    "\n",
    "    def get_standard_level_array(self):\n",
    "        return self.standard_level.split(\".\")\n",
    "\n",
    "def get_last_number(arr):\n",
    "    if arr and arr[-1].replace(\"_\", \"\").isdigit():\n",
    "        return int(arr[-1].replace(\"_\", \"\"))\n",
    "    return None\n",
    "\n",
    "def detect_text_level(content, last_level):\n",
    "    s_number_enum_array = \"1234567890\"\n",
    "    b_number_enum_array = \"一二三四五六七八九十百千万零两壹贰叁肆伍陆柒捌玖拾佰仟\"\n",
    "    split_enums = r\")）、,，\\.\"\n",
    "    letter_enums = \"a-zA-Z\"\n",
    "    weight = 1\n",
    "\n",
    "    temp_compiles = []\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"\\s*(?P<i>总则)\\s*\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>第[N]+章)\\s+\"))\n",
    "\n",
    "    weight += 1\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>第[N]+[S]{1})\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>第[N]+部分)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>第[N]+节)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>第[N]+部分[S]{1})\\s+\"))\n",
    "\n",
    "    weight += 1\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>第[n]+章)\\s+\"))\n",
    "\n",
    "    weight += 1\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>第[n]+[S]{1})\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>第[n]+部分)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>第[n]+节)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>第[n]+部分[S]{1})\\s+\"))\n",
    "\n",
    "    weight += 1\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[N]+、)\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[N]+[S]{1})\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[N]+[S]{1}[N]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[N]+[S]{1}[N]+[S]{1}[N]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[N]+[S]{1}[N]+[S]{1}[N]+[S]{1}[N]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[N]+[S]{1}[N]+[S]{1}[N]+[S]{1}[N]+[S]{1}[N]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[N]+[S]{1}[N]+[S]{1}[N]+[S]{1}[N]+[S]{1}[N]+[S]{1}[N]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[N]+[S]{1}[N]+[S]{1}[N]+[S]{1}[N]+[S]{1}[N]+[S]{1}[N]+[S]{1}[N]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[A]+[S]{1})\\s+\"))\n",
    "\n",
    "    weight += 1\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[n]+、)\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[n]+[S]{1})\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[n]+[S]{1}[n]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[n]+[S]{1}[n]+[S]{1}[n]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[n]+[S]{1}[n]+[S]{1}[n]+[S]{1}[n]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[n]+[S]{1}[n]+[S]{1}[n]+[S]{1}[n]+[S]{1}[n]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[n]+[S]{1}[n]+[S]{1}[n]+[S]{1}[n]+[S]{1}[n]+[S]{1}[n]+)\\s+\"))\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[n]+[S]{1}[n]+[S]{1}[n]+[S]{1}[n]+[S]{1}[n]+[S]{1}[n]+[S]{1}[n]+)\\s+\"))\n",
    "\n",
    "    weight += 1\n",
    "    temp_compiles.append(CompileItem(100 * weight, r\"(?P<i>[A]+[S]{1})\\s+\"))\n",
    "\n",
    "    compiles = []\n",
    "    for compile_item in temp_compiles:\n",
    "        pattern_text = compile_item.pattern_text.replace(\"A\", letter_enums).replace(\"n\", s_number_enum_array).replace(\"N\", b_number_enum_array).replace(\"S\", split_enums)\n",
    "        new_compile_item = CompileItem(compile_item.level, pattern_text)\n",
    "        compiles.append(new_compile_item)\n",
    "\n",
    "    compiles.sort(key=lambda x: len(x.pattern_text), reverse=True)\n",
    "\n",
    "    current_level = None\n",
    "    builder = []\n",
    "\n",
    "    for compile_item in compiles:\n",
    "        matcher = compile_item.pattern.search(content)\n",
    "        if matcher:\n",
    "            number_value = matcher.group(\"i\")\n",
    "            start = matcher.start()\n",
    "            end = matcher.end()\n",
    "            if start == 0:\n",
    "                builder.append(number_value)\n",
    "                current_level = TxtLevel(None, compile_item.level, number_value, number_value, True)\n",
    "                break\n",
    "\n",
    "    if current_level and last_level:\n",
    "        if current_level.weight == last_level.weight:\n",
    "            if last_level.parent is None:\n",
    "                return current_level\n",
    "            return TxtLevel(last_level.parent, current_level.weight, current_level.raw_level, last_level.parent.standard_level + \".\" + current_level.standard_level, True)\n",
    "        elif current_level.weight > last_level.weight:\n",
    "            return TxtLevel(last_level, current_level.weight, current_level.raw_level, last_level.standard_level + \".\" + current_level.standard_level, True)\n",
    "        else:\n",
    "            parent = last_level.parent\n",
    "            while parent and parent.weight != current_level.weight:\n",
    "                parent = parent.parent\n",
    "            if parent and parent.standard_level_array and current_level.standard_level_array and get_last_number(parent.standard_level_array()) + 1 == get_last_number(current_level.standard_level_array()):\n",
    "                if parent.parent is None:\n",
    "                    return TxtLevel(None, current_level.weight, current_level.raw_level, current_level.standard_level, True)\n",
    "                else:\n",
    "                    return TxtLevel(parent.parent, current_level.weight, current_level.raw_level, parent.parent.standard_level + \".\" + current_level.standard_level, True)\n",
    "            else:\n",
    "                return current_level\n",
    "\n",
    "    if current_level is None and (not \".\" in content and not \"。\" in content) and (content.endswith(\"：\") or content.endswith(\":\")):\n",
    "        if last_level.standard_level.endswith(\"__\"):\n",
    "            sub_level_number = get_last_number(last_level.standard_level_array())\n",
    "            return TxtLevel(last_level, last_level.weight + 1, \"\", last_level.standard_level.replace(f\".{sub_level_number}\", f\".{sub_level_number + 1}\"), True)\n",
    "    else:\n",
    "        return TxtLevel(last_level, last_level.weight + 1, \"\", last_level.standard_level + \".1__\", True)\n",
    "    \n",
    "    return current_level\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.TxtLevel object at 0x000001CA77B8FB30>\n",
      "\n"
     ]
    }
   ],
   "source": [
    "last_level = TxtLevel(None, 0, \"\", \"1__\", True)\n",
    "content = \"第一章\"\n",
    "result = detect_text_level(content, last_level)\n",
    "print(result)\n",
    "print(result.raw_level if result else \"No level detected\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
